#ifndef INPUTOUTPUT_H_
#define INPUTOUTPUT_H_

#include <cstring>
#include <cstdlib>

#include "Data.h"

using namespace std;

/*
 * =====================================================================================
 *        Class:  DataSet
 *  Description:  Classe que representa um conjunto de entradas/saídas
 * =====================================================================================
 */
class DataSet
{

public:

    /*-----------------------------------------------------------------------------
     *  Contrói um DataSet vazio
     *-----------------------------------------------------------------------------*/
    DataSet(uint nInVars, uint nOutVars);

    /*-----------------------------------------------------------------------------
     *  Carrega o conjunto de entradas/saídas de um arquivo
     *-----------------------------------------------------------------------------*/
    DataSet(const char *file, int filetype);

    /*-----------------------------------------------------------------------------
     *  Randomiza
     *-----------------------------------------------------------------------------*/
    void randomize();

    /*-----------------------------------------------------------------------------
     *  Retorna a entrada/saída de índice i
     *-----------------------------------------------------------------------------*/
    DataPtr get(uint i) { return dataSet[i]; }

    /*-----------------------------------------------------------------------------
     *  Retorna a entrada/saída de índice aleatório i
     *-----------------------------------------------------------------------------*/
    uint getRandom(uint i) { return random[i]; }

    /*-----------------------------------------------------------------------------
     *  Retorna o número de entradas/saídas
     *-----------------------------------------------------------------------------*/
    uint size() { return dataSet.size(); }

    /*-----------------------------------------------------------------------------
     *  Retorna o número de variáveis de entrada
     *-----------------------------------------------------------------------------*/
    uint getNInVars() { return nInVars; }

    /*-----------------------------------------------------------------------------
     *  Retorna o número de variáveis de saída
     *-----------------------------------------------------------------------------*/
    uint getNOutVars() { return nOutVars; }

    /*-----------------------------------------------------------------------------
     *  Adiciona uma data a estrutura
     *-----------------------------------------------------------------------------*/
    void addData(DataPtr data) { random.push_back(dataSet.size()); dataSet.push_back(data); }

    /*-----------------------------------------------------------------------------
     *  Calcula a taxa de sucesso
     *-----------------------------------------------------------------------------*/
    void calcSuccessRate(double tolerance);

    /*-----------------------------------------------------------------------------
     *  Seta a taxa de sucesso
     *-----------------------------------------------------------------------------*/
    void setSuccessRate(double successRate) { this->successRate = successRate; }

    /*-----------------------------------------------------------------------------
     *  Retorna a taxa de sucesso
     *-----------------------------------------------------------------------------*/
    double getSuccessRate() { return successRate; }

    /*-----------------------------------------------------------------------------
     *  Verifica se o cálculo da rede neural foi bem sucedido para todas
     *  entradas/saídas
     *-----------------------------------------------------------------------------*/
    bool hasSucceeded(double tolerance);

    /*-----------------------------------------------------------------------------
     *  Seta o tempo de treinamento ou de teste
     *-----------------------------------------------------------------------------*/
    void setTime(double time) { this->time = time; }

    /*-----------------------------------------------------------------------------
     *  Retorna o tempo de treinamento ou teste
     *-----------------------------------------------------------------------------*/
    double getTime() { return time; }

    /*-----------------------------------------------------------------------------
     *  Seta número de iterações de treinamento
     *-----------------------------------------------------------------------------*/
    void setNIterations(uint nIterations) { this->nIterations = nIterations; }

    /*-----------------------------------------------------------------------------
     *  Retorna número de iterações de treinamento
     *-----------------------------------------------------------------------------*/
    uint getNIterations() { return nIterations; }

    /*-----------------------------------------------------------------------------
     *  Salva as entradas/saídas em um arquivo
     *-----------------------------------------------------------------------------*/
    void saveToFile(const char *file);

    /*-----------------------------------------------------------------------------
     *  Imprime informações na tela
     *-----------------------------------------------------------------------------*/
    void print(bool printNeuralOutput = false);

private:

    /*-----------------------------------------------------------------------------
     *  Número de variáveis de entrada
     *-----------------------------------------------------------------------------*/
    uint nInVars;

    /*-----------------------------------------------------------------------------
     *  Número de variáveis de saída
     *-----------------------------------------------------------------------------*/
    uint nOutVars;

    /*-----------------------------------------------------------------------------
     *  Tempo total de teste ou de treinamento
     *-----------------------------------------------------------------------------*/
    double time;

    /*-----------------------------------------------------------------------------
     *  Número de iterações
     *-----------------------------------------------------------------------------*/
    uint nIterations;

    /*-----------------------------------------------------------------------------
     *  Taxa de sucesso
     *-----------------------------------------------------------------------------*/
    double successRate;

    /*-----------------------------------------------------------------------------
     *  Tipo do conjunto (entrada ou saída)
     *-----------------------------------------------------------------------------*/
    int filetype;

    /*-----------------------------------------------------------------------------
     *  Vetor para randomização
     *-----------------------------------------------------------------------------*/
    vuint random;

    /*-----------------------------------------------------------------------------
     *  Conjunto de dados
     *-----------------------------------------------------------------------------*/
    vector<DataPtr> dataSet;

};

#endif /* INPUTOUTPUT_H_ */
